﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit.RevitExtension;
using Transfer.CommonUnit;
using Transfer.Utils;

namespace Transfer.SingleFloor
{
	public class GeneralElementsTransfer
	{
		public bool CoypWindows
		{
			set
			{
				this.m_CoypWindows = value;
			}
		}

		public bool CopyDoors
		{
			set
			{
				this.m_CopyDoors = value;
			}
		}

		public bool CopyOpenings
		{
			set
			{
				this.m_CopyOpenings = value;
			}
		}

		public GeneralElementsTransfer(ExternalCommandData cmdData, Transform transformMatrix)
		{
			this.m_Revit = cmdData;
			this.m_Doc = this.m_Revit.Application.ActiveUIDocument.Document;
			this.InitTransformOperateInfo(transformMatrix);
		}

		public bool TrasformGeneralElements(ICollection<ElementId> elementsIdList)
		{
			Document document = this.m_Revit.Application.ActiveUIDocument.Document;
			if (elementsIdList.Count < 1)
			{
				return true;
			}
			bool result;
			try
			{
				ICollection<ElementId> collection = ElementTransformUtils.CopyElements(document, elementsIdList, this.m_FarawayMoveVector);
				if (this.m_TransformOperate.IsMirrored())
				{
					int elementCount = MirrorOperater.GetElementCount(document);
					RevitVersionFuncs.MirrorElements(document, collection, this.m_TransformOperate.MirrorPlane, false);
					List<ElementId> elementsIdAfter = MirrorOperater.GetElementsIdAfter(elementCount, document);
					if (elementsIdAfter.Count < 1)
					{
						return false;
					}
					foreach (ElementId elementId in collection)
					{
						document.Delete(elementId);
					}
					collection.Clear();
					foreach (ElementId item in elementsIdAfter)
					{
						collection.Add(item);
					}
				}
				if (this.m_TransformOperate.IsRotated())
				{
					ElementTransformUtils.RotateElements(document, collection, this.m_TransformOperate.RotateAxis, this.m_TransformOperate.RotatedAngle);
				}
				XYZ xyz = -this.m_FarawayMoveVector;
				if (this.m_TransformOperate.IsMoved())
				{
					xyz += this.m_TransformOperate.MoveVector;
				}
				ElementTransformUtils.MoveElements(document, collection, xyz);
				this.DeleteBaseWallElements(collection, this.m_CoypWindows, this.m_CopyDoors, this.m_CopyOpenings);
				Common.UpdateModel(this.m_Revit.Application.ActiveUIDocument, false);
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		private void InitTransformOperateInfo(Transform transformMatrix)
		{
			Plane mirrorPlane = null;
			XYZ origin = transformMatrix.Origin;
			if (transformMatrix.BasisZ.IsAlmostEqualTo(-XYZ.BasisZ))
			{
				mirrorPlane = RevitVersionFuncs.CreatePlanByNormalAndOrigin(XYZ.BasisY, this.m_FarawayMoveVector);
			}
			double angle = Geometry.getAngle(XYZ.Zero, transformMatrix.BasisX);
			Line rotateAxis = YJKLineEx.YJKGetUnBound(this.m_FarawayMoveVector, XYZ.BasisZ);
			XYZ moveVector = origin;
			this.m_TransformOperate = new GeneralElementsTransfer.TransformOperate(mirrorPlane, angle, rotateAxis, moveVector);
		}

		private void DeleteBaseWallElements(ICollection<ElementId> newElementIds, bool copyWindows, bool copyDoors, bool copyOpenings)
		{
			if (newElementIds.Count == 0)
			{
				return;
			}
			Document document = this.m_Revit.Application.ActiveUIDocument.Document;
			List<ElementId> list = new List<ElementId>();
			foreach (ElementId elementId in newElementIds)
			{
				Element element = document.GetElement(elementId);
				if (!(element.GetType() != typeof(Wall)))
				{
					Wall wall = element as Wall;
					if (!copyWindows)
					{
						list.AddRange(this.GetBaseWallElements(document, wall, typeof(FamilyInstance), BuiltInCategory.OST_Windows));
					}
					if (!copyDoors)
					{
						list.AddRange(this.GetBaseWallElements(document, wall, typeof(FamilyInstance), BuiltInCategory.OST_Doors));
					}
					if (!copyOpenings)
					{
						list.AddRange(this.GetBaseWallElements(document, wall, typeof(Opening), BuiltInCategory.OST_SWallRectOpening));
						list.AddRange(this.GetBaseWallElements(document, wall, typeof(Opening), BuiltInCategory.OST_ArcWallRectOpening));
					}
				}
			}
			this.DeleteElements(document, list);
		}

		private void DeleteElements(Autodesk.Revit.DB.Document doc, List<ElementId> elements)
		{
			if (elements.Count == 0)
			{
				return;
			}
			foreach (ElementId elementId in elements)
			{
				try
				{
					doc.Delete(elementId);
				}
				catch (Exception)
				{
				}
			}
		}

		private List<ElementId> GetBaseWallElements(Autodesk.Revit.DB.Document doc, Wall wall, Type type, BuiltInCategory category)
		{
			List<ElementId> list = new List<ElementId>();
			ElementCategoryFilter elementCategoryFilter = new ElementCategoryFilter(category);
			IEnumerable<Element> enumerable = new FilteredElementCollector(doc).OfClass(type).WherePasses(elementCategoryFilter).ToElements();
			ElementId elementId = wall.get_Parameter(BuiltInParameter.ID_PARAM).AsElementId();
			foreach (Element element in enumerable)
			{
				ElementId obj;
				if (element.GetType() == typeof(FamilyInstance))
				{
					obj = (element as FamilyInstance).Host.get_Parameter(BuiltInParameter.ID_PARAM).AsElementId();
				}
				else
				{
					if (!(element.GetType() == typeof(Opening)))
					{
						continue;
					}
					obj = (element as Opening).Host.Id;
				}
				if (elementId.Equals(obj))
				{
					list.Add(element.Id);
				}
			}
			return list;
		}

		private ExternalCommandData m_Revit;

		private Document m_Doc;

		private GeneralElementsTransfer.TransformOperate m_TransformOperate;

		private List<Element> m_SelectElements = new List<Element>();

		private XYZ m_FarawayMoveVector = XYZ.BasisX * 1000.0;

		private bool m_CoypWindows = true;

		private bool m_CopyDoors = true;

		private bool m_CopyOpenings = true;

		private class TransformOperate
		{
			public Plane MirrorPlane
			{
				get
				{
					return this.m_MirrorPlane;
				}
			}

			public double RotatedAngle
			{
				get
				{
					return this.m_RotatedAngle;
				}
			}

			public Line RotateAxis
			{
				get
				{
					return this.m_RotateAxis;
				}
			}

			public XYZ MoveVector
			{
				get
				{
					return this.m_MoveVector;
				}
			}

			public TransformOperate(Plane mirrorPlane, double rotatedAngle, Line rotateAxis, XYZ moveVector)
			{
				this.m_MirrorPlane = mirrorPlane;
				this.m_RotatedAngle = rotatedAngle;
				this.m_RotateAxis = rotateAxis;
				this.m_MoveVector = moveVector;
			}

			public bool IsMirrored()
			{
				return this.m_MirrorPlane != null;
			}

			public bool IsRotated()
			{
				return !Geometry.IsEqual(this.m_RotatedAngle, 0.0);
			}

			public bool IsMoved()
			{
				return !Geometry.IsEqual(this.m_MoveVector.GetLength(), 0.0);
			}

			private Plane m_MirrorPlane;

			private double m_RotatedAngle;

			private Line m_RotateAxis;

			private XYZ m_MoveVector;
		}
	}
}
